#!/usr/bin/env python3
# PYTHON_ARGCOMPLETE_OK

#
# Copyright (C) 2019 GreenWaves Technologies
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import sys

import argcomplete
import argparse

from errors import FatalError, InputError
import common
import json_tools as js

# Sub commands
import gen_readfs
import gen_flash_image
import gen_partition
import run
import elf2bin
import run
import flash

__version__ = "0.1"

PYTHON2 = sys.version_info[0] < 3  # True if on pre-Python 3
if PYTHON2:
    print("Fatal error: Gapy needs to be run with python version 3")
    exit(1)

def appendOperations(parser, subparsers, config):
    #
    # Gen ReadFS command
    #
    
    parserGenReadFS = subparsers.add_parser(
        'gen_readfs',
        help = 'Generate a ReadFS file system image.')
    gen_readfs.appendArgs(parserGenReadFS)
    
    #
    # Gen flash image command
    #
    
    parserGenFlashImage = subparsers.add_parser(
        'gen_flash_image',
        help = 'Build a Gap flash image from binary files and partition images.')
    if config:
        flashConfig = config.get(config.get_str("runner/boot/device"))
    else:
        flashConfig = None
    gen_flash_image.appendArgs(parserGenFlashImage, flashConfig)

    #
    # Flash command
    #
    
    parserFlash = subparsers.add_parser(
        'flash',
        help = 'flash image to the target')
    flash.appendArgs(parserFlash, config)
    
    #
    # Gen partition command
    #
    
    parserGenPartition = subparsers.add_parser(
        'gen_partition',
        help = 'Build and convert partition image')
    gen_partition.appendArgs(parserGenPartition)

    #
    # elf2bin command
    #
    
    parserElf2bin = subparsers.add_parser(
        'elf2bin',
        help = 'Convert an ELF App to a binary.')
    elf2bin.appendArgs(parserElf2bin)
    
    #
    # Run command
    #
    
    parserRun = subparsers.add_parser(
        'run',
        help = 'Run application to a specific platform.')
    
    run.appendArgs(parser, parserRun, config)


def main(custom_commandline = None):
    """
    Main function for Gapy
    
    custom_commandline - Optional override for default arguments parsing (that uses sys.argv), can be a list of custom arguments
    as strings. Arguments and their values need to be added as individual items to the list e.g. "--target gapuino" thus
    becomes ['--target', 'gapuino'].
    """
    parser = argparse.ArgumentParser(
        description = 'Gapy v%s - GAP8 Utility' % __version__,
        prog = 'gapy',
        fromfile_prefix_chars = '@',
        formatter_class = argparse.ArgumentDefaultsHelpFormatter)
    
    #
    # Common options shared by Gapy and sub-command #
    common.appendCommonOptions(parser)
    
    #
    # Fetch target Json config
    #
    config = common.importConfig(parser)
    
    #
    # Append sub-commands
    #
    subparsers = parser.add_subparsers(
        dest = 'operation',
        help = 'Gapy operation. Run gapy {command} -h for additional help')
    appendOperations(parser, subparsers, config)
    
    # Every operation matches a module function called operationFunc.
    for operation in subparsers.choices.keys():
        assert operation in globals(), "%s should be a module function" % operation
    
    argcomplete.autocomplete(parser)
    args = parser.parse_args(custom_commandline)
    
    common.parseOptions(args, config)

    if args.operation is None:
        parser.print_help()
        sys.exit(1)
    
    operationFunc = globals()[args.operation].operationFunc
    operationFunc(args, config)
    try:  # Clean up AddrFilenamePairAction files
        for address, argfile in args.addr_filename:
            argfile.close()
    except AttributeError:
        pass


if __name__ == '__main__':
    try:
        main()
    except InputError as e:
        print('\nInput fatal error: ', e, file = sys.stderr)
        sys.exit(1)
    except FatalError as e:
        print('\nA fatal error occurred: ', e)
        sys.exit(2)
